package cn.metona.utils;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.*;

public final class NetUtils {

    // 私有构造方法，防止实例化
    private NetUtils() {
        throw new UnsupportedOperationException("Utility class");
    }

    // 获取本地主机的IP地址
    public static Optional<String> getLocalIpAddress() {
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            return Optional.of(localHost.getHostAddress());
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return Optional.empty();
        }
    }

    // 获取公网IP地址
    public static Optional<String> getPublicIpAddress() {
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://api.ipify.org?format=text"))
                    .GET()
                    .build();

            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            client.close();
            return Optional.of(response.body());
        } catch (Exception e) {
            e.printStackTrace();
            return Optional.empty();
        }
    }

    // 检查指定端口是否可用
    public static boolean isPortAvailable(int port) {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            serverSocket.setReuseAddress(true);
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    // 发送HTTP GET请求
    public static String sendHttpGetRequest(String url) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        client.close();
        return response.body();
    }

    // 获取HTTP响应头
    public static Map<String, List<String>> getHttpHeaders(String url) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .method("HEAD", HttpRequest.BodyPublishers.noBody())
                .build();

        HttpResponse<Void> response = client.send(request, HttpResponse.BodyHandlers.discarding());
        client.close();
        return response.headers().map();
    }

    // 检查URL是否有效
    public static boolean isUrlValid(String url) {
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .method("HEAD", HttpRequest.BodyPublishers.noBody())
                    .build();

            HttpResponse<Void> response = client.send(request, HttpResponse.BodyHandlers.discarding());
            client.close();
            return response.statusCode() == 200;
        } catch (Exception e) {
            return false;
        }
    }

    // 下载文件
    public static void downloadFile(String url, Path destination) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
        Files.copy(response.body(), destination, StandardCopyOption.REPLACE_EXISTING);
        client.close();
    }

    // Ping主机
    public static boolean pingHost(String host, int timeout) {
        try {
            InetAddress address = InetAddress.getByName(host);
            return address.isReachable(timeout);
        } catch (IOException e) {
            return false;
        }
    }

    // 获取本地网络接口的MAC地址
    public static Optional<String> getMacAddress() {
        try {
            NetworkInterface network = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
            if (network != null) {
                byte[] mac = network.getHardwareAddress();
                if (mac != null) {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < mac.length; i++) {
                        sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
                    }
                    return Optional.of(sb.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Optional.empty();
    }

    // 获取所有网络接口信息
    public static void listNetworkInterfaces() throws SocketException {
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface networkInterface = interfaces.nextElement();
            System.out.println("Interface: " + networkInterface.getName());
            System.out.println("  Display Name: " + networkInterface.getDisplayName());
            System.out.println("  MTU: " + networkInterface.getMTU());
            System.out.println("  Is Up: " + networkInterface.isUp());
            System.out.println("  Is Loopback: " + networkInterface.isLoopback());
            System.out.println("  MAC Address: " + getMacAddress(networkInterface));
            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                System.out.println("  IP Address: " + address.getHostAddress());
            }
            System.out.println();
        }
    }

    // 获取指定网络接口的MAC地址
    private static String getMacAddress(NetworkInterface networkInterface) {
        try {
            byte[] mac = networkInterface.getHardwareAddress();
            if (mac != null) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < mac.length; i++) {
                    sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
                }
                return sb.toString();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "N/A";
    }

    // 获取域名对应的IP地址
    public static Optional<String> getIpByHostname(String hostname) {
        try {
            InetAddress address = InetAddress.getByName(hostname);
            return Optional.of(address.getHostAddress());
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return Optional.empty();
        }
    }

    // 获取HTTP响应状态码
    public static int getHttpStatusCode(String url) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .method("HEAD", HttpRequest.BodyPublishers.noBody())
                .build();

        HttpResponse<Void> response = client.send(request, HttpResponse.BodyHandlers.discarding());
        client.close();
        return response.statusCode();
    }

    // 设置代理并发送HTTP请求
    public static String sendHttpGetRequestWithProxy(String url, String proxyHost, int proxyPort) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newBuilder()
                .proxy(ProxySelector.of(new InetSocketAddress(proxyHost, proxyPort)))
                .connectTimeout(Duration.ofSeconds(10))
                .build();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        client.close();
        return response.body();
    }

    // 获取SSL证书信息
    public static void getSslCertificateInfo(String url) throws IOException {
        try {
            URL httpsUrl = new URL(url);
            HttpsURLConnection connection = (HttpsURLConnection) httpsUrl.openConnection();
            connection.connect();
            Certificate[] certificates = connection.getServerCertificates();
            for (Certificate cert : certificates) {
                if (cert instanceof X509Certificate x509Cert) {
                    System.out.println("Subject DN: " + x509Cert.getSubjectX500Principal());
                    System.out.println("Issuer DN: " + x509Cert.getIssuerX500Principal());
                    System.out.println("Valid From: " + x509Cert.getNotBefore());
                    System.out.println("Valid Until: " + x509Cert.getNotAfter());
                    System.out.println("Serial Number: " + x509Cert.getSerialNumber());
                    System.out.println();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取网络接口的MTU（最大传输单元）
    public static Optional<Integer> getMtu(String interfaceName) throws SocketException {
        NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName);
        if (networkInterface != null) {
            return Optional.of(networkInterface.getMTU());
        }
        return Optional.empty();
    }

    // 获取网络接口的广播地址
    public static Optional<String> getBroadcastAddress(String interfaceName) throws SocketException {
        NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName);
        if (networkInterface != null) {
            for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) {
                InetAddress broadcast = address.getBroadcast();
                if (broadcast != null) {
                    return Optional.of(broadcast.getHostAddress());
                }
            }
        }
        return Optional.empty();
    }

    // 解析URL并获取主机名和端口
    public static void parseUrl(String url) throws URISyntaxException {
        URI uri = new URI(url);
        String host = uri.getHost();
        int port = uri.getPort();
        String scheme = uri.getScheme();

        System.out.println("Scheme: " + scheme);
        System.out.println("Host: " + host);
        System.out.println("Port: " + (port == -1 ? "default" : port));
    }

    public static void main(String[] args) {
        // 示例用法
        try {
            listNetworkInterfaces();
        } catch (SocketException e) {
            e.printStackTrace();
        }

        Optional<String> ip = getIpByHostname("www.google.com");
        ip.ifPresentOrElse(
                address -> System.out.println("Google IP Address: " + address),
                () -> System.out.println("Could not resolve hostname.")
        );

        try {
            int statusCode = getHttpStatusCode("https://www.example.com");
            System.out.println("HTTP Status Code: " + statusCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

        try {
            String response = sendHttpGetRequestWithProxy("https://www.example.com", "proxy.example.com", 8080);
            System.out.println("HTTP GET Response with Proxy: " + response);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

        try {
            getSslCertificateInfo("https://www.example.com");
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            Optional<Integer> mtu = getMtu("eth0");
            mtu.ifPresentOrElse(
                    value -> System.out.println("MTU: " + value),
                    () -> System.out.println("Could not retrieve MTU.")
            );
        } catch (SocketException e) {
            e.printStackTrace();
        }

        try {
            Optional<String> broadcastAddress = getBroadcastAddress("eth0");
            broadcastAddress.ifPresentOrElse(
                    address -> System.out.println("Broadcast Address: " + address),
                    () -> System.out.println("Could not retrieve broadcast address.")
            );
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
}
